M2.855 · Modelos avanzados de minería de datos · PEC3

2020-2 · Máster universitario en Ciencia de datos (Data science)

Estudios de Informática, Multimedia y Telecomunicación

 

PEC 3: Métodos supervisados

Francisco Javier Melchor González

En esta práctica veremos diferentes métodos supervisados y trataremos de optimizar diferentes métricas. Veremos como los diferentes modelos clasifican los puntos y con cuales obtenemos mayor precisión. Después aplicaremos todo lo que hemos aprendido hasta ahora a un dataset nuevo simulando un caso práctico real.

  1. Exploración de algoritmos supervisados
    1. Naive-Bayes
    2. $k$ vecinos más próximos
    3. Support vector machines
    4. Árboles de decisión
    5. Random forest / Gradient boosting
  2. Implementación del caso práctico
    1. Análisis descriptivo
    2. Preprocesamiento de los datos
    3. Entrenamiento del modelo
    4. Predicción de nuevos casos

Importante: Cada uno de los ejercicios puede suponer varios minutos de ejecución, por lo que la entrega se hará en formato notebook y en formato html donde se vea el código y los resultados, junto con los comentarios de cada ejercicio. Para exportar el notebook a html se puede hacer desde el menú File $\to$ Download as $\to$ HTML.

1. Exploración de algoritmos supervisados (5 puntos)

En la PEC anterior trabajamos con el dataset MNIST, compuesto de miles de dígitos manuscritos del 0 al 9. Donde cada imagen se compone de 784 píxeles (imágenes de 28 x 28). Redujimos a dos dimensiones el dataset utilizando diferentes técnicas de clustering, y vimos que con UMAP conseguíamos separar las clases (dígitos) bastante bien en 2D.

En este primer ejercicio iremos un paso más allá, utilizaremos diferentes métodos supervisados para predecir las diferentes clases. El objetivo será que, dada una imagen nueva, el algoritmo sea capaz de clasificar correctamente el número de la imagen.

Empezamos cargando el dataset y visualizando un ejemplo de cada dígito.

Este dataset es muy grande, con una muestra obtendremos resultados muy similares y nos permitirá trabajar con más agilidad.

Implementación:

Dividid el dataset en dos subconjuntos, train (80% de los datos) y test (20% de los datos). Nombrad los conjuntos como: X_train, X_test, y_train, y_test. Utilizad la opción random_state = 24.

Podéis utilizar la implementación train_test_split de sklearn.

Para poder visualizar los resultados de cada algoritmo supervisado, reduciremos el dataset anterior a dos dimensiones, tal como hicimos en la PEC2.

A lo largo de los ejercicios aprenderemos a ver gráficamente las fronteras de decisión que nos devuelven los diferentes modelos. Para ello utilizaremos la función definida a continuación, que sigue los siguientes pasos:

Una vez hecho esto, ya podemos hacer el gráfico de las fronteras de decisión y añadir los puntos reales. Así veremos las áreas que el modelo considera que son de una clase y las que considera que son de otra. Al poner encima los puntos veremos si los clasifica correctamente en el área que les corresponde.

1.1. Gaussian Naïve Bayes

El objetivo de este primer ejercicio es entender el funcionamiento del algoritmo Naïve-Bayes, un algoritmo peculiar ya que se basa completamente en teoría de probabilidades.

Implementación:

Con el dataset de train reducido a dos dimensiones, entrenad un modelo Naïve-Bayes y representad gráficamente la frontera de decisión con el de test. Podéis utilizar el clasificador GaussianNB de sklearn.

Calculad el accuracy del modelo obtenido sobre train y test y la matriz de confusión sobre test. Podéis utilizar accuracy_score y confusion_matrix del paquet metrics de sklearn.

Análisis:

Análisis del ejercicio.

1.2. KNN

El objetivo de este segundo ejercicio es entender el funcionamiento del KNN, intuir sus principales ventajas o desventajas y entender la influencia de los parámetros de los que está compuesto.

K-Nearest-Neighbor es un algoritmo basado en instancia de tipo supervisado.

Vamos a ver qué significa esto:

¿Cómo funciona KNN?

Implementación:

Con el dataset de train reducido a dos dimensiones, entrenad un modelo KNN con n_neighbors = 2 y representad gráficamente la frontera de decisión con el de test.

Podéis utilizar el clasificador KNeighborsClassifier de sklearn.

En el modelo entrenado, hemos fijado el parámetro n_neighbors de forma arbitraria. Pero podría ser que con otro valor obtuviéramos una mejor predicción.

Para conocer el valor óptimo de los parámetros de un modelo (hyperparameter tunning) se suele utilizar una búsqueda de rejilla (grid search). Es decir, entrenar un modelo para cada combinación de hiperparámetros posible y evaluarlo utilizando validación cruzada (cross validation) con 4 particiones estratificadas. Posteriormente, se elige la combinación de hiperparàmetres que mejores resultados haya obtenido.

En este caso sólo queremos optimizar un hiperparámetro:

Implementación:

Cálculo del valor óptimo del hiperparámetro k (n_neighbors). Utilizad una búsqueda de rejilla con validación cruzada para encontrar el valor óptimo de k. Por cada valor, calculad su promedio y la desviación estándar. Implementad un heatmap para visualizar la precisión según los diferentes valores del hiperparámetro.

Puede utilizar el módulo GridSearchCV de sklearn el cálculo del mejor hiperparámetro, y heatmap de Seaborn.

Implementación:

Con el mejor hiperparámetro encontrado, volved a entrenar un clasificador KNN (con train) y representar las fronteras de decisión con los puntos de test.

Calcular el accuracy del modelo obtenido sobre test y la matriz de confusión. Podéis utilizar accuracy_score y confusion_matrix de metrics de sklearn.

Análisis:

Análisis del ejercicio:

1.3. SVM

Las Support Vector Machine se fundamentan en el Máximal Margin Classifier, que a su vez, se basan en el concepto de hiperplano.

En un espacio p-dimensional, un hiperplano se define como un subespacio plano y afín de dimensiones p-1. El término afín significa que el subespacio no debe pasar por el origen. En un espacio de dos dimensiones, el hiperplano es un subespacio de 1 dimensión, es decir, una recta. En un espacio tridimensional, un hiperplano es un subespacio de dos dimensiones, un plano convencional. Para dimensiones p>3 no es intuitivo visualizar un hiperplano, pero el concepto de subespacio con p-1 dimensiones se mantiene.

La definición de hiperplano para casos perfectamente separables linealmente resulta en un número infinito de posibles hiperplanos, lo que hace necesario un método que permita seleccionar uno de ellos como clasificador óptimo.

La solución a este problema consiste en seleccionar como clasificador óptimo al que se conoce como maximal margin hyperplane o hiperplano óptimo de separación, que se corresponde con el hiperplano que se encuentra más alejado de todas las observaciones de entrenamiento. Para obtenerlo, se debe calcular la distancia perpendicular de cada observación a un determinado hiperplano. La menor de estas distancias (conocida como margen) determina cómo de lejos está el hiperplano de las observaciones de entrenamiento. El maximal margin hyperplane se define como el hiperplano que consigue un mayor margen, es decir, que la distancia mínima entre el hiperplano y las observaciones es lo más grande posible. Aunque esta idea suena razonable, no es posible aplicarla, ya que habría infinitos hiperplanos contra los que medir las distancias. En su lugar, se recurre a métodos de optimización.

El proceso de optimización tiene la peculiaridad de que sólo las observaciones que se encuentran justo al margen o que lo violan influyen sobre el hiperplano. A estas observaciones se les conoce como vectores soporte (vectors suport) y son las que definen el clasificador obtenido.

Los kernels en SVM

Hay veces en que no hay manera de encontrar un hiperplano que permita separar dos clases. En estos casos decimos que las clases no son linealmente separables. Para resolver este problema podemos utilizar el truco del núcleo .

El truco del núcleo (kernel trick) consiste en utilizar una dimensión nueva en la que podamos encontrar un hiperplano para separar las clases. Se puede ver un un ejemplo en: https://www.youtube.com/watch?v=OdlNM96sHio

Al igual que en el algoritmo visto anteriormente (KNN), las SVM también dependen de varios hiperparámetros.

En este caso intentaremos optimizar dos hiperparámetros:

Al igual que en el caso anterior, para validar el rendimiento del algoritmo con cada combinación de hiperparámetros utilizaremos validación cruzada (cross-validation) con 4 particiones estratificadas.

Implementación:

Cálcular del valor óptimo de los hiperparámetros C y gama. Utilizad una búsqueda de rejilla con validación cruzada para encontrar los valores óptimos. Para cada combinación de valores, calcular su promedio y la desviación estándar. Haced un heatmap para visualizar la precisión según los diferentes valores de los hiperparámetros.

Podéis utilizar el módulo GridSearchCV de sklearn el cálculo de los mejores hiperparámetros con el clasificador SVC (de SVM de sklearn), y heatmap de Seaborn.

Implementación:

Con la mejor combinación de hiperparámetros encuentrada, entrenad un clasificador SVM (con train) y representar las fronteras de decisión con los puntos de test.

Calcular el accuracy del modelo obtenido sobre test y la matriz de confusión. Puede utilizar accuracy_score y confusion_matrix de metrics de sklearn.

Análisis:

Análisis del ejercicio.

1.4. Árboles de decisión

Los árboles de decisión son modelos predictivos formados por reglas binarias (si / no) con las que se consigue repartir las observaciones en función de sus atributos y predecir así el valor de la variable respuesta.

Los árboles pueden ser clasificadores (para clasificar clases, tales como nuestro ejemplo), o bien regresores (para predecir variables continuas).

Construcción de un árbol

La creación de las ramificaciones de los árboles se logra mediante el algoritmo de recursive binary splitting. Este algoritmo consta de tres pasos principales:

Evitando el overfitting

El proceso de construcción de árboles descrito tiende a reducir rápidamente el error de entrenamiento, por lo que generalmente el modelo se ajusta muy bien a las observaciones utilizadas como entrenamiento (conjunto de train). Como consecuencia, los árboles de decisión tienden al overfitting.

Para prevenirlo, utilizaremos dos hiperparámetros:

Implementación:

Calculad el valor óptimo de los hiperparámetros max_depth y min_samples_split. Utilizad una búsqueda de rejilla con validación cruzada para encontrar los valores óptimos. Para cada combinación de valores, calcular su promedio y la desviación estándar. Haced un heatmap para visualizar la precisión según los diferentes valores de los hiperparámetros.

Pódeis utilizar el módulo GridSearchCV de sklearn el cálculo de los mejores hiperparámetros con el clasificador DecisionTreeClassifier (de tree de sklearn), y heatmap de Seaborn.

Implementación:

Con la mejor combinación de hiperparámetros encontrados, entrenad un clasificador DecisionTreeClassifier (con train) y representar las fronteras de decisión con los puntos de test.

Calcular el accuracy del modelo obtenido sobre test y la matriz de confusión. Puede utilizar accuracy_score y confusion_matrix de metrics de sklearn.

Análisis:

Análisis del ejercicio.

1.5. Mejorando los árboles de decisión

En la práctica, casi nunca se utiliza un solo árbol de decisión, sino que se combinan muchos árboles para obtener mejores resultados. Hay dos maneras de combinar árboles:

Ambos métodos los estudiaremos más en detalle en la próxima PEC, pero en esta haremos un vistazo a los beneficios que nos aporta utilizar combinaciones de árboles respecto un solo árbol.

Al tratarse de árboles, sigue siendo importante optimizar max_depth y min_samples_split, pero en este caso añadiremos un hiperparámetro más. Para simplificar, de los dos parámetros anteriores optimizaremos sólo max_depth:

Implementación:

Escoged uno de los dos algoritmos mencionados: RandomForestClassifier o GradientBoostingClassifier. Calculad el valor óptimo de los hiperparámetros n_estimators y max_depth. Utilizad una búsqueda de rejilla con validación cruzada para encontrar los valores óptimos. Para cada combinación de valores, calcular su promedio y la desviación estándar. Haced un heatmap para visualizar la precisión según los diferentes valores de los hiperparámetros.

Podéis utilizar el módulo GridSearchCV de sklearn para el cálculo de los mejores hiperparámetros con el clasificador RandomForestClassifier o GradientBoostingClassifier (de ensemble de sklearn), y heatmap de Seaborn.

Nota: al utilizar tantos árboles, el cross validation con todas las combinaciones de parámetros es más costosa que en los ejemplos anteriores, y por lo tanto tardará más en ejecutarse.

Implementación:

Con la mejor combinación de hiperparámetros encontrada, entrenad un clasificador DecisionTreeClassifier (con train) y representar las fronteras de decisión con los puntos de test.

Calcular el accuracy del modelo obtenido sobre test y la matriz de confusión. Puede utilizar accuracy_score y confusion_matrix de metrics de sklearn.

Análisis:

Análisis del ejercicio.

2. Implementación del caso práctico (5 puntos)

Para este ejercicio se proporciona un dataset con datos sobre diferentes clientes de un banco que quieren comprar un piso, y si el banco les ha concedido la hipoteca o no.

La información es la siguiente:

Empezamos leyendo el dataset y viendo una muestra de las primeras filas.

2.1. Análisis descriptivo

Cuando se nos proporciona un dataset, antes de empezar a hacer nada, es muy importante hacer un análisis exploratorio para conocer los datos con los que trabajaremos.

Implementación:

Calculad las frecuencias de la variable target (hipoteca). Analizar la distribución de las otras variables con gráficos de barras las variables categóricas y con histogramas las variables numéricas.

2.2. Preprocesamiento de los datos

Una vez hecho un primer análisis, se trata de "limpiar" el dataset y adaptarlo a nuestras necesidades (en este caso, predecir si se concederá la hipoteca o no).

Implementación:

Comprueba si hay valores null. En caso de haberlos, elimina las filas correspondientes.

Implementación:

El siguiente paso sería ver la correlación entre todas las features numéricas. Esto se hace para asegurar que no hay dos variables muy relacionadas entre sí, ya que en tal caso se debería seleccionar una de las dos o combinarlas en una nueva.

Implementación:

Mostrad la correlación entre todas las features numéricas. Si hay dos con una correlación superior al 80%, eliminar una de las dos.

Podéis utilizar heatmap de Seaborn, para verlas en un mapa de colores.

Ya tenemos las variables finales con las que trabajaremos. Vamos a observar ahora cuál es la relación de cada una de ellas con el target.

Implementación:

Repite los diagramas de barras y los histogramas, separando por colores la variable target (dentro del mismo gráfico, diferenciar entre hipoteca-sí y hipoteca-no).

Nota: Puedes utilizar el parámetro alpha para que se vean los dos gráficos a la vez.

Conclusiones obtenidas:

Finalmente, sólo nos queda pasar las variables categóricas a numéricas. Observad que a pesar de que todas las variables tengan números, esto no quiere decir que sean numéricas. Por ejemplo, la variable estado_civil tiene los valores 0-1-2, que sería lo mismo que si tuviera los valores soltero-casado-divorciado. Hay otras variables donde esto no ocurre, por ejemplo el número de hijos, que a pesar de ser categórica sí que son números, ya que es ordinal. La manera de diferenciarlo es, en el caso del número de hijos, 1 hijo es menos que 2 hijos, mientras que con el estado civil no hay un orden.

Una manera de pasar las variables categóricas en numéricas es aplicando one-hot encoding. Por ejemplo, en el caso de la variable estado_civil, lo que se haría sería crear tres columnas nuevas: soltero, casado y divorciado. Estas columnas tendrían los valores 0-1, por ejemplo, en el caso de la columna soltero tendría el valor 1 cuando estado_civil = soltero, y cero en otro caso.

Implementación:

Aplica one-hot-encoding a las variables categóricas que lo requieran. No olvidéis eliminar las variables originales!

Podéis utilizar OneHotEncoder de sklearn.preprocessing.

Análisis:

2.3. Entrenamiento de un modelo

Ahora que ya tenemos el dataset limpio y hemos hecho un análisis de las diferentes variables, podemos proceder a entrenar un modelo para predecir si se concede una hipoteca o no.

Probaremos con 2 modelos diferentes e interpretaremos los resultados.

Para empezar, separamos el dataset entre train y test.

Implementación:

Dividid el dataset en dos subconjuntos: train (80% de los datos) y test (20% de los datos). Nombrad los conjuntos: X_train, X_test, y_train, y_test. Utilizad la opción random_state = 24.

Podéis utilizar la implementación train_test_split de sklearn.

Implementación:

Utilizad un árbol de decisión simple con max_depth = 5 para acotar el dataset "hipotecas" sobre el conjunto de train. Dibujad el árbol de decisión. Calculad el accuray y la matriz de confusión sobre train y sobre test.

Para dibujar el árbol, podéis guiaros con este enlace: https://towardsdatascience.com/visualizing-decision-trees-with-python-scikit-learn-graphviz-matplotlib-1c50b4aa68dc

tree_1

Análisis:

Interpretad el árbol de decisión:

Implementación:

Usad Random Forest o Gradient Boosting para acotar el dataset "hipotecas". Esta vez vamos a optimizar el modelo para obtener los mejores resultados posibles. Tal y como hemos visto en el ejercicio anterior, recuerda seguir los siguientes pasos:

Un Random Forest / Gradient Boosting no es tan fácil de interpretar como un simple Decision Tree. No podemos dibujar el árbol, porque son combinaciones de muchos árboles, pero si que podemos saber cuáles han sido las variables más decisivas a la hora de generar el modelo. Para saberlo, no podemos hacerlo a ojo mirando cómo se divide el árbol, sino que lo podemos consultar al modelo mediante la feature importance de este.

Implementación:

Muestra cada variable del modelo fitado, junto con su feature importance.

Análisis:

Interpreta el clasificador:

2.4. Predicción de nuevos casos

Hasta ahora hemos entrenado un modelo y hemos evaluado en test para hacernos una idea de la precisión de nuestro modelo con datos reales. Ahora vamos a utilizarlo.

Implementación:

Suponed que trabajáis en un banco y os visitan clientes que quieren una hipoteca. Aunque se ha de realizar un estudio a fondo de cada caso, así a priori utilizad el clasificador entrenado para tener una idea de si se les concederá la hipoteca o no.